package main

import (
	"bufio"
	"fmt"
	"github.com/noaway/dateparse"
	"io"
	"os"
	"regexp"
	"sort"
	"strings"
	"time"
)

type node struct {
	ip    string
	cuont int
}

type yh struct {
	ip string
	m  map[string]int
}

func main() {
	//时间
	start, err := dateparse.ParseAny("May 3, 2012")
	if err != nil {
		panic(err.Error())
	}
	end := start.AddDate(0, 0, 20)

	fileName := "D:\\work\\go\\access.log"
	file, err := os.OpenFile(fileName, os.O_RDWR, 0666)
	if err != nil {
		fmt.Println("Open file error!", err)
		return
	}
	defer file.Close()

	dlIpMap := make(map[string]string)
	bdIpnodeMap := make(map[string]*node)
	yhIpMap := make(map[string]*yh)

	buf := bufio.NewReader(file)

	r1 := regexp.MustCompile("07/May/2012")
	r2 := regexp.MustCompile("www.bing.com")
	r3 := regexp.MustCompile(`http?://\w+\.\w+\.\w+`)

	defer func() {
		i := recover()
		if i != nil {
			fmt.Println(i)
		}

		fmt.Println("07/May/2012 独立IP的数量：", len(dlIpMap))

		bdIpnodeArr := make([]*node, 0)
		for _, v := range bdIpnodeMap {
			bdIpnodeArr = append(bdIpnodeArr, v)
		}
		sort.Slice(bdIpnodeArr, func(i, j int) bool {
			return bdIpnodeArr[i].cuont > bdIpnodeArr[j].cuont
		})

		fmt.Println("前三个的ip")
		for i := 0; i <= 2 && len(bdIpnodeArr) > i; i++ {
			fmt.Println(bdIpnodeArr[i].ip)
		}

		//获取最接近的ip
		sr := "207.46.13.96"
		i2 := yhIpMap[sr]

		var maxvalue float32 = 0.0
		user := ""
		delete(yhIpMap, sr)
		for _, v := range yhIpMap {
			//x 相交的数量，b一起的数量
			var x float32 = 0
			var b float32 = float32(len(v.m) + len(i2.m))
			for url, _ := range v.m {
				_, ok := i2.m[url]
				if ok {
					x++
				}
			}
			var s float32 = x / b
			if s > maxvalue {
				maxvalue = s
				user = v.ip
			}
		}
		fmt.Println("最大的s是:"+user+"   最大值为:", maxvalue)
	}()

	for {
		line, err := buf.ReadString('\n')
		line = strings.TrimSpace(line)
		//获取满足：某天的日志

		split := strings.Split(line, " - - ")
		//解析ip
		ip := split[0]

		//第一题
		if r1.MatchString(line) {
			dlIpMap[ip] = ""
		}

		datestr := strings.Split(split[1], "]")[0][1:]
		//将时间字符串转成time
		date := paretDataStr(datestr)

		//第二题
		//判断是否在这段时间里面
		if (start.Before(date) || end.After(date)) && r2.MatchString(line) {
			n, ok := bdIpnodeMap[ip]
			if !ok {
				n = &node{ip: ip, cuont: 0}
			}
			n.cuont++
			bdIpnodeMap[ip] = n
		}

		//第三题
		//假设解析到 http
		url := r3.FindString(line)
		y, ok := yhIpMap[ip]
		if !ok {
			y = &yh{ip: ip, m: make(map[string]int)}
		}
		y.m[url] = 1
		yhIpMap[ip] = y

		if err != nil {
			if err == io.EOF {
				fmt.Println("File read ok!")
				break
			} else {
				fmt.Println("Read file error!", err)
				return
			}
		}
	}

}

//01/May/2012:00:36:26 -0700
func paretDataStr(str string) time.Time {

	datastr := strings.Split(str, ":")[0]
	split := strings.Split(datastr, "/")
	//"Nov 8, 2017",

	str1 := split[1] + " " + split[0] + ", " + split[2]
	start, err := dateparse.ParseAny(str1)
	if err != nil {
		day := 0
		day = int((split[0][0] - 48) * 10)
		split[0] = split[0][1:]

		str1 := split[1] + " " + split[0] + ", " + split[2]
		start, _ := dateparse.ParseAny(str1)

		return start.AddDate(0, 0, day)
	}
	return start
}
